package com.chenjl.trace;

import java.util.Map;
import java.util.Map.Entry;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.chenjl.trace.context.TraceContext;
import com.chenjl.trace.enums.AnnotationEnum;
import com.chenjl.trace.enums.SpanTypeEnum;
import com.chenjl.trace.generate.IdGenerator;
import com.chenjl.trace.generate.TraceTime;
import com.chenjl.trace.model.Endpoint;
import com.chenjl.trace.model.Span;
import com.google.gson.Gson;
/**
 * trace
 * 2018-9-7 16:39:18
 * @author chenjinlong
 */
public class Tracer {
	private static final Logger log = LoggerFactory.getLogger(Tracer.class);
	
	public static final ThreadLocal<TraceContext> threadLocal = new InheritableThreadLocal<TraceContext>() {
		@Override
		protected TraceContext initialValue() {
			return new TraceContext();
		}
	};
	
	
	/**
	 * 获取root的span
	 * @return
	 */
	public static final Span getRootSpan() {
		return threadLocal.get().getRoot();
	}
	/**
	 * 开启root span，所有请求的源头
	 * @param spanName
	 * @param endpoint
	 * @param annotationEnum
	 * @return 返回spanId
	 */
	public static final String beginRoot(String spanName,Endpoint endpoint,AnnotationEnum annotationEnum,
			SpanTypeEnum spanTypeEnum) {
		String spanId = IdGenerator.get();
		
		Span span = new Span();
		span.setTraceId(IdGenerator.get());
		span.setId(spanId);
		span.setName(spanName);
		span.setSpanType(spanTypeEnum.getValue());
		span.setTimestamp(TraceTime.get());
		span.addAnnotation(endpoint,annotationEnum);
		
		TraceContext traceContext = threadLocal.get();
		traceContext.setRoot(span);
		traceContext.addSpan(span);
		
		return spanId;
	}
	/**
	 * 开启一个非root的span
	 * @param traceId
	 * @param parentId
	 * @param spanName
	 * @param endpoint
	 * @param annotationEnum
	 * @return 返回spanId
	 */
	public static final String begin(String traceId,String parentId,String spanName,Endpoint endpoint,
			AnnotationEnum annotationEnum,SpanTypeEnum spanTypeEnum) {
		String spanId = IdGenerator.get();
		
		Span span = new Span();
		span.setTraceId(traceId);
		span.setParentId(parentId);
		span.setId(spanId);
		span.setName(spanName);
		span.setSpanType(spanTypeEnum.getValue());
		span.setTimestamp(TraceTime.get());
		span.addAnnotation(endpoint,annotationEnum);
		
		TraceContext traceContext = threadLocal.get();
		traceContext.addSpan(span);
		
		return spanId;
	}
	/**
	 *  根据spanId结束，计算耗时和添加结束的事件标记
	 * @param spanId
	 * @param endpoint
	 * @param annotationEnum
	 */
	public static final void end(String spanId,Endpoint endpoint,AnnotationEnum annotationEnum) {
		TraceContext traceContext = threadLocal.get();
		Span span = traceContext.getSpanMap().get(spanId);
		
		if(span != null) {
			span.setDuration(TraceTime.get() - span.getTimestamp());
			span.addAnnotation(endpoint,annotationEnum);
		}
	}
	/**
	 *  根据spanId结束，计算耗时和添加结束的事件标记
	 * @param spanId
	 * @param endpoint
	 * @param annotationEnum
	 * @param binaryAnnotations RPC附带信息
	 */
	public static final void end(String spanId,Endpoint endpoint,AnnotationEnum annotationEnum,Map<String,String> datas) {
		TraceContext traceContext = threadLocal.get();
		Span span = traceContext.getSpanMap().get(spanId);
		
		if(span != null) {
			span.setDuration(TraceTime.get() - span.getTimestamp());
			span.addAnnotation(endpoint,annotationEnum);
			
			for(Entry<String,String> entry : datas.entrySet()) {
				String key = entry.getKey();
				String value = entry.getValue();
				
				span.addBinaryAnnotation(endpoint,key,value);
			}
		}
	}
	/**
	 * 本次请求结束，输出span
	 */
	public static final void clear() {
		TraceContext traceContext = threadLocal.get();
		Gson gson = new Gson();
		log.info(gson.toJson(traceContext.getSpans()));
		
		threadLocal.remove();
	}
}